Using Server-Sent-Events (SSE) in .NET
This article mainly introduces how to implement real-time communication in .NET using SSE.
Comparison of SSE and Other Real-time Communication Methods
In JavaScript, there are three common ways to implement real-time communication:
Polling: The Client sends requests to the Server periodically to request and receive data. This method often leads to excessive requests and responses, consuming significant resources.
Server-Sent-Events (SSE): A unidirectional connection where the Server pushes updated data to the Client. This method has the following advantages: unidirectional connection, reduced server burden, and only one TCP connection, which reduces bandwidth waste.
WebSocket: A bidirectional connection established between the Client and the Server, allowing both parties to send data at any time. WebSocket can reduce network traffic and improve efficiency.
SSE JavaScript Implementation
SSE has three default events: open, error, and message. Below is a simple JavaScript example:
SSE Code Example
const sse = new EventSource('Your API Url');
// Listen to the open event, triggered when the connection is successful
sse.addEventListener('open', function (e) {
console.log('SSE connection opened');
});
// Listen to the error event, triggered when a connection error occurs
sse.addEventListener('error', function (e) {
console.log('SSE connection error');
});
// Listen to the message event, triggered when a message is received
sse.addEventListener('message', function (e) {
console.log('SSE message received', e);
const data = JSON.parse(e.data);
const messageElement = document.createElement('div');
messageElement.textContent = data.message;
document.body.appendChild(messageElement);
});
// Listen to the custom end event
sse.addEventListener('end', function (e) {
console.log('SSE custom end', e);
sse.close();
});The withCredentials Property
When creating a Server-Sent Events (SSE) object, you can use the withCredentials property to specify whether to send CORS authentication information when making cross-origin requests. This property has no effect in same-origin scenarios.
WARNING
When using SSE with cross-origin requests, the Server-side Header also needs to be configured for CORS accordingly.
const sse = new EventSource('Your API Url', { withCredentials: true } );Implementing an SSE Server in .NET
- The Server sends a message containing an event and data to the Client, and the Client can use the EventSource object to receive these messages. Both event and data are optional, and each message ends with an empty line.
- The Content-Type returned by the SSE Server is
text/event-stream.
Implementation using ASHX (Generic Handler)
ASHX is a feature of ASP.NET Web Forms that can easily handle Web requests. In SSE applications, you can use ASHX to handle SSE requests. Below is a simple ASHX code example:
public class SseHandler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
// Set the response Content-Type to text/event-stream
context.Response.ContentType = "text/event-stream";
context.Response.CacheControl = "no-cache";
// Simulate an SSE event stream, sending one message per second
int count = 0;
while (count < 10) {
count++;
context.Response.Write("data: " + "{\"message\": \"Hello SSE " + count + "\"}\n\n");
context.Response.Flush();
System.Threading.Thread.Sleep(1000);
}
// Return a custom end event; the JavaScript example above will Close SSE here
context.Response.Write("event: end\ndata: {}\n\n");
context.Response.Flush();
context.Response.End();
}
public bool IsReusable {
get {
return false;
}
}
}TIP
Each message ends with an empty line, so the first \n indicates a line break in the message, and the second \n indicates the end of the message.
Implementation using ASP.NET Core Web API
[ApiController]
[Route("[controller]")]
public class SseController : ControllerBase {
[HttpGet]
public async Task GetAsync() {
// Set the response Content-Type to text/event-stream
Response.Headers.Add("Content-Type", "text/event-stream;");
Response.Headers.Add("Cache-Control", "no-cache");
// Simulate an SSE event stream, sending one message per second
int count = 0;
while (count < 10) {
count++;
await Response.WriteAsync($"data: " + "{\"message\": \"Hello SSE " + count + "\"}\n\n");
await Response.Body.FlushAsync();
await Task.Delay(TimeSpan.FromSeconds(1));
}
// Return a custom end event; the JavaScript example above will Close SSE here
await Response.WriteAsync("event: end\ndata: {}\n\n");
await Response.Body.FlushAsync();
}
}Changelog
- 2023-03-15 Initial document creation.
- 2024-02-17 Updated content related to withCredentials.
